<template>
  <div class="card content-box">
    <div class="cabinetLayout">
      <TreeFilter
        label="name"
        title=""
        disabled="disabled"
        :data="commandTree"
        :multiple="true"
        :needSearch="false"
        :onlyLeafNodeHighlight="false"
        @change="_commandChange"
      />
      <div class="layoutInfoWrap">
        <div class="layoutInfo">
          <div class="layout">
            <div
              class="layoutCon"
              v-infinite-scroll="_loadMore"
              :infinite-scroll-delay="200"
              :infinite-scroll-immediate="false"
              :infinite-scroll-distance="10"
              v-loading="loading"
            >
              <div class="layoutForm">
                <el-collapse v-model="activeNames">
                  <el-form :model="form">
                    <div v-for="item in form" :key="item.title">
                      <el-collapse-item :name="item.title">
                        <template #title>
                          <div class="collapseItemTitle">
                            <span> {{ item.title }}</span>
                            <span :class="[item.reqStatus === 'suc' ? 'reqStatusSuc' : 'reqStatusFail']" v-if="item.reqStatus">
                              {{ item.reqStatus === "suc" ? "（成功）" : `(失败：${item.failTip})` }}
                            </span>
                          </div>
                        </template>
                        <div class="layoutItemTitle" v-if="item.dataItemList_in && item.dataItemList_in.length > 0">
                          <img class="titleIcon" src="@/assets/images/titleIcon.png" /><span>入参</span>
                        </div>
                        <div class="layoutItem" v-for="val in item.dataItemList_in" :key="val.itemId">
                          <div class="layoutItem__labName">{{ val.itemName }}</div>
                          <el-form-item class="layoutItem__con">
                            <el-select v-model="val.itemValue" v-if="val.itemType === 1">
                              <el-option :label="v.lable" :value="v.value" v-for="v in val.selectList" :key="v.value" />
                            </el-select>
                            <el-date-picker
                              placeholder=""
                              :type="val.itemType === 7 ? 'date' : 'datetime'"
                              :format="val.itemType === 7 ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
                              :value-format="val.itemType === 7 ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
                              v-model="val.itemValue"
                              v-else-if="val.itemType === 7 || val.itemType === 8"
                            />
                            <el-input v-model="val.itemValue" v-else></el-input>
                          </el-form-item>
                        </div>
                        <div class="layoutItemTitle" v-if="item.dataItemList_out && item.dataItemList_out.length > 0">
                          <img class="titleIcon" src="@/assets/images/titleIcon.png" /><span>出参</span>
                        </div>
                        <div class="layoutItem" v-for="val in item.dataItemList_out" :key="val.itemId">
                          <div class="layoutItem__labName">{{ val.itemName }}</div>
                          <el-form-item class="layoutItem__con">
                            <el-input v-model="val.itemValue" readonly></el-input>
                          </el-form-item>
                        </div>
                      </el-collapse-item>
                    </div>
                  </el-form>
                </el-collapse>
              </div>
            </div>
          </div>
          <div class="deviceMenuList">
            <TreeFilter
              label="name"
              title=""
              disabled="disabled"
              :data="objectTree"
              :multiple="true"
              :needSearch="false"
              :onlyLeafNodeHighlight="false"
              @change="_objectChange"
            />
          </div>
        </div>
      </div>
    </div>
    <HandlerBar :handlerBtns="handlerBtns" />
  </div>
</template>

<script setup lang="tsx" name="electrityMeterControl">
import { onMounted, reactive, ref } from "vue";
import TreeFilter from "@/components/TreeFilter/index.vue";
import HandlerBar from "@/components/HandlerBar/index.vue";
import { Position } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { getCommandTree, getObjectTree, meterControl } from "@/api/modules/device1Manage/index";
import { ResultData, Control } from "@/api/interface";

const commandTree = ref([]);
const objectTree = ref([]);
const commandList = ref([]);
const objectList = ref([]);
const originalForm: any = ref([]);
const form: any = ref([]);
const originalFormVals = ref([]);
const formVals: any = ref([]);
const activeNames: any = ref([]);
const commandCheckedVals: any = ref([]);
const objectCheckedVals: any = ref([]);
const pageSize = ref(5);
const loading = ref(false);

/**
 * 提交数据
 */
const _submit = async () => {
  let isReturn: boolean = false;
  let paramsList: Control.ReqControlParams[] = [];
  const ruleMap: Map<number, RegExp> = new Map([
    [
      2,
      /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
    ],
    [
      3,
      /^(254|252|248|240|224|192|128|0)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(254|252|248|240|224|192|128|0)$/
    ],
    [4, /^(192\.168(\.(\d|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))){2})$/],
    [5, /^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/],
    [6, /^([0-9a-fA-F]{2}(:|-)){5}[0-9a-fA-F]{2}$/],
    [9, /(^[+]{0,1}1[0-2]|[1-9])$/],
    [10, /^([+]{0,1}([0-5]?[0-9])|60)$/],
    [11, /^([+]{0,1}([0-5]?[0-9])|60)$/],
    [13, /^[+]{0,1}(\d+)$|^[+]{0,1}(\d+\.\d+)$/],
    [14, /^[+]{0,1}[0-9]+(.[0-9]{1})?$/],
    [15, /^[+]{0,1}[0-9]+(.[0-9]{1})?$/]
  ]);
  const lastFormVals = originalForm.value.concat(originalFormVals.value).splice(form.value.length);
  const totalFormVals = form.value.concat(lastFormVals);

  totalFormVals.forEach((item: any) => {
    if (!isReturn) {
      try {
        item.dataItemList_in.forEach((val: any) => {
          if (!val.isEmpty) {
            if (!val.itemValue && val.itemValue !== 0) {
              ElMessage.error(`${item.title}-${val.itemName}：输入值为空`);
              isReturn = true;
              throw Error();
            }
            const ruleItem: any = ruleMap.get(val?.itemType);
            if (ruleMap.has(val.itemType) && !ruleItem.test(val.itemValue)) {
              ElMessage.error(`${item.title}-${val.itemName}：输入值格式不正确`);
              isReturn = true;
              throw Error();
            }
          }
        });
      } catch (err: any) {
        console.log(err.message);
      }
    }

    const dataItemList = item.dataItemList_in.map((val: any) => {
      return {
        itemId: val.itemId,
        itemValue: val.itemValue
      };
    });
    try {
      if (isReturn) throw Error();
      let paramsData: Control.ReqControlParams = { commandId: item.commandId, meterId: item.meterId };
      if (dataItemList && dataItemList.length > 0) {
        paramsData.dataItemList = dataItemList;
      }
      paramsList.push(paramsData);
    } catch (err: any) {
      console.log(err.message);
    }
  });

  if (!isReturn) {
    reqFunc(paramsList, totalFormVals, 0);
  }
};
/**
 * 加载更多
 */
const _loadMore = () => {
  form.value = form.value.concat(formVals.value.splice(0, pageSize.value));
};
/**
 * 底部操作栏按钮组
 */
const handlerBtns = reactive([
  {
    name: "下发",
    type: "primary",
    icon: Position,
    plain: false,
    class: "save",
    func: _submit
  }
]);

/**
 * 命令树选择
 */
const _commandChange = function (opts: { data: any; nodes: any }): void {
  const { nodes } = opts;
  const ids = nodes.checkedKeys;
  commandCheckedVals.value = [];

  commandList.value.forEach((item: any) => {
    ids.forEach((val: any, idx: number) => {
      if (item.commandId === val) {
        commandCheckedVals.value.push({ ...item, isParent: nodes.checkedNodes[idx].isParent });
      }
    });
  });
  form.value = form.value.filter((item: any) => {
    if (ids.includes(item.commandId)) {
      return item;
    }
  });
  originalForm.value = JSON.parse(JSON.stringify(form.value));
  loading.value = true;
  setTimeout(() => {
    loading.value = false;
  }, pageSize.value * 100);
  setTimeout(() => {
    setFormData();
  }, pageSize.value * 100 + 100);
};
/**
 * 设备对象选择
 */
const _objectChange = function (opts: { data: any; nodes: any }): void {
  const { nodes } = opts;
  const ids = nodes.checkedKeys;
  objectCheckedVals.value = [];

  objectList.value.forEach((item: any) => {
    ids.forEach((val: any, idx: number) => {
      if (item.id === val && val !== "-") {
        objectCheckedVals.value.push({ ...item, isParent: nodes.checkedNodes[idx].isParent });
      }
    });
  });
  form.value = form.value.filter((item: any) => {
    if (ids.includes(item.meterId)) {
      return item;
    }
  });
  originalForm.value = JSON.parse(JSON.stringify(form.value));
  loading.value = true;
  setTimeout(() => {
    loading.value = false;
  }, pageSize.value * 100);
  setTimeout(() => {
    setFormData();
  }, pageSize.value * 100 + 100);
};

/**
 * 处理form数据
 */
const setFormData = () => {
  let dataItemList_in: any[] = [];
  let dataItemList_out: any[] = [];
  formVals.value = [];
  objectCheckedVals.value.forEach((item: any) => {
    commandCheckedVals.value.forEach((val: any) => {
      const title = `${item.name}-${val.dataName}`;
      const isMatch = form.value.some((v: any) => {
        return v.commandId === val.commandId && v.meterId === item.id;
      });
      if (isMatch) return false;
      if (!val.isParent) {
        if (val.dataItemList) {
          val.dataItemList.forEach((v: any) => {
            v.inOut === "in" ? dataItemList_in.push(v) : dataItemList_out.push(v);
            switch (v.itemType) {
              case 1:
                v.itemValue = v.defaultValue ?? "";
                if (v.selectList && v.selectList.length > 0) {
                  v.selectList.some((o: any) => {
                    if (o.isSelected) {
                      v.itemValue = o.value;
                      return false;
                    }
                  });
                }
                break;
              default:
                v.itemValue = v.defaultValue ?? "";
                break;
            }
          });
          val.dataItemList_in = dataItemList_in;
          val.dataItemList_out = dataItemList_out;
        }
        formVals.value.push({
          title,
          commandId: val.commandId,
          meterId: item.id,
          dataItemList: val.dataItemList ?? [],
          dataItemList_in: val.dataItemList_in ?? [],
          dataItemList_out: val.dataItemList_out ?? [],
          reqStatus: val.reqStatus ?? "",
          failTip: val.failTip ?? ""
        });
      }
      activeNames.value.push(title);
    });
  });
  originalFormVals.value = JSON.parse(JSON.stringify(formVals.value));
  if (form.value.length < pageSize.value) {
    form.value = form.value.concat(formVals.value.splice(0, pageSize.value - form.value.length));
  } else {
    form.value = form.value.concat(formVals.value.splice(0, pageSize.value));
  }
};
/**
 * 处理服务端数据匹配TreeFilter组件格式
 */
const matchData = (list: any, id: string, name: string) => {
  return list.map((item: any) => {
    if (item.children) {
      return {
        isParent: true,
        id: item[id],
        name: item[name],
        disabled: item.disabled ?? false,
        children: matchData(item.children, id, name)
      };
    } else {
      return {
        isParent: false,
        id: item[id],
        name: item[name],
        disabled: item.disabled ?? false
      };
    }
  });
};
/**
 * 展开树
 */
const getFlatMapData = (list: any) => {
  let newList = JSON.parse(JSON.stringify(list));
  return newList.flatMap((item: any) => [item, ...(item.children ? getFlatMapData(item.children) : [])]);
};
/**
 * 递归请求
 */
const reqFunc = async (paramsList: any[], totalFormVals: any[], count: number) => {
  if (paramsList.length <= 0) return;
  let tempFormVal = count >= form.value.length ? formVals.value[count - form.value.length] : form.value[count];
  const stateFunc = (res: any) => {
    if (res?.result) {
      const { dataItemMap } = res?.result;
      totalFormVals.forEach((item: any) => {
        item.dataItemList_in.forEach((val: any) => {
          if (dataItemMap[val.itemId]) {
            val.itemValue = dataItemMap[val.itemId].itemValue;
          }
        });
        item.dataItemList_out.forEach((val: any) => {
          if (dataItemMap[val.itemId]) {
            val.itemValue = dataItemMap[val.itemId].itemValue;
          }
        });
      });
      tempFormVal.reqStatus = "suc";
    } else {
      tempFormVal.reqStatus = "fail";
      tempFormVal.failTip = res.msg;
    }
    count++;

    if (count >= paramsList.length) {
      return;
    }
    reqFunc(paramsList, totalFormVals, count);
  };
  await meterControl(paramsList[count]).then(stateFunc, stateFunc);
};
onMounted(async () => {
  const { dataTree } = (await getCommandTree({ objectStyle: 5 })) as ResultData;
  commandTree.value = matchData(dataTree, "commandId", "dataName");
  commandList.value = getFlatMapData(dataTree);
  commandList.value.forEach((item: any) => {
    let dataItemList_in: any[] = [];
    let dataItemList_out: any[] = [];
    if (item.dataItemList) {
      item.dataItemList.forEach((val: any) => {
        val.inOut === "in" ? dataItemList_in.push(val) : dataItemList_out.push(val);
        switch (val.itemType) {
          case 1:
            val.itemValue = val.defaultValue ?? "";
            if (val.selectList && val.selectList.length > 0) {
              val.selectList.some((v: any) => {
                if (v.isSelected) {
                  val.itemValue = v.value;
                  return false;
                }
              });
            }
            break;
          default:
            val.itemValue = val.defaultValue ?? "";
            break;
        }
      });
      item.dataItemList_in = dataItemList_in;
      item.dataItemList_out = dataItemList_out;
    }
  });

  const { dataList } = (await getObjectTree()) as ResultData;
  const objectData = dataList.map((item: any) => {
    let stationList: any[] = [];

    item.stationList &&
      item.stationList.forEach((val: any) => {
        if (val.meterId) {
          stationList.push({
            id: val.meterId,
            name: val.stationName,
            disabled: !item.connectStatus
          });
        }
      });
    return {
      id: "-",
      name: item.deviceName,
      children: stationList || [],
      disabled: !item.connectStatus || !stationList.length
    };
  });

  objectTree.value = matchData(objectData, "id", "name");
  objectList.value = getFlatMapData(objectData);
});
</script>

<style scoped lang="scss">
@import "./index.scss";
</style>
